using System;
using System.Diagnostics;
using System.Management.Automation;             //Windows PowerShell namespace.
using System.ComponentModel;
using System.Collections.Generic;
using System.Collections.ObjectModel;

using VirtualOps.Base;

namespace VmWareVix.Commands
{

  [Cmdlet(VerbsCommon.Get, "VM", DefaultParameterSetName = "Name")]
  public class GetVMCommand : PSCmdlet
  {
    #region Parameters
    ////////////////////////////////////////////////////////////////////////////
    [Parameter(Position = 0,
           ParameterSetName = "Name",
           ValueFromPipeline = true,
           ValueFromPipelineByPropertyName = true)]
    [ValidateNotNullOrEmpty]
    public string[] Name
    {
      get { return _names; }
      set { _names = value; }
    }
    private string[] _names;

    [Parameter(ParameterSetName = "InputObject",
               Mandatory = true,
               ValueFromPipeline = true)]
    public IVirtualMachine[] Input
    {
      get { return inputObjects; }
      set { inputObjects = value; }
    }
    private IVirtualMachine[] inputObjects;

    #endregion


    protected override void ProcessRecord()
    {
      Collection<IVirtualMachine> matchingVms;

      WriteDebug("Obtaining list of matching VM objects...");

      // Select method based on parameter set.
      switch (ParameterSetName)
      {
        case "Name":
          matchingVms = GetMatchingVmsByName();
          break;
        case "InputObject":
          matchingVms = GetProcessesByInput();
          break;
        default:
          ThrowTerminatingError(
              new ErrorRecord(
                  new ArgumentException("Bad ParameterSetName"),
                  "UnableToAccessVmList",
                  ErrorCategory.InvalidOperation,
                  null));
          return;
      }

      WriteDebug("Outputting matching VM objects...");

      //  matchingVms.Sort(ProcessComparison); (this was in M$ example)

      foreach (IVirtualMachine vm in matchingVms)
      {
        WriteObject(vm);
      }
    }

    private Collection<IVirtualMachine> GetProcessesByInput()
    {
      WriteWarning("The method or operation is not implemented.");
      return new Collection<IVirtualMachine>();
    }

    private Collection<IVirtualMachine> GetMatchingVmsByName()
    {
      Collection<IVirtualMachine> vms = GetVms(); 
      Collection<IVirtualMachine> matchingVms = new Collection<IVirtualMachine>();

      if (null == Name) return vms;

      foreach (string pattern in Name)
      {
        WriteVerbose("Finding matches for VM name \"" + pattern + "\".");

        // WildCard serach on the available processes
        WildcardPattern wildcard =
               new WildcardPattern(pattern,
                   WildcardOptions.IgnoreCase);

        bool matchFound = false;

        foreach (IVirtualMachine vm in vms)
        {
            // Remove the vm from the allVms list 
            // so that it's not tested again.
            if (vm.Name.Length == 0) vms.Remove(vm);

            // Perform a wildcard search on this particular 
            // VM and check whehter this matches the 
            // pattern specified.
            if (!wildcard.IsMatch(vm.Name))
              continue;

            WriteDebug("Found matching VM Name"
                         + vm.Name + ".");

            matchFound = true;
            matchingVms.Add(vm);
        }

        if (!matchFound &&
              !WildcardPattern.ContainsWildcardCharacters(pattern))
        {
          WriteError(new ErrorRecord(
                     new ArgumentException("Cannot find VM name "
                        + "\"" + pattern + "\"."),
                   "ProcessNameNotFound",
                   ErrorCategory.ObjectNotFound,
                   pattern));
        }
      } // End foreach(string...).

      return matchingVms;
    }

    private Collection<IVirtualMachine> GetVms()
    {
      //TODO: support using alternative VmServer taken from a parameter
      //Add VmmServer parameter
      VmServer server = VmServer.Current;
      if (server == null)
      {
        throw new VirtualOpsException(String.Format("{0}{1}{2}",
          "VmmServer is not set. ", 
          "You must be connected to a virtual machine management system to run this command." ,
          "Use Get-VmmServer to connect."));
      }
      Collection<IVirtualMachine> vms = new Collection<IVirtualMachine>(server.GetAllVms()); 
      return vms;
    }
  }
}
